package com.xul.srb.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xul.common.exception.Assert;
import com.xul.common.result.ResponseEnum;
import com.xul.common.util.MD5;
import com.xul.common.util.RegexValidateUtils;
import com.xul.srb.base.uitl.JwtUtils;
import com.xul.srb.core.mapper.UserAccountMapper;
import com.xul.srb.core.mapper.UserInfoMapper;
import com.xul.srb.core.mapper.UserLoginRecordMapper;
import com.xul.srb.core.pojo.entity.UserAccount;
import com.xul.srb.core.pojo.entity.UserInfo;
import com.xul.srb.core.pojo.entity.UserLoginRecord;
import com.xul.srb.core.pojo.query.UserInfoQuery;
import com.xul.srb.core.pojo.vo.LoginVO;
import com.xul.srb.core.pojo.vo.RegisterVO;
import com.xul.srb.core.pojo.vo.UserIndexVO;
import com.xul.srb.core.pojo.vo.UserInfoVO;
import com.xul.srb.core.service.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author xul
 * @since 2021-11-06
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UserAccountMapper userAccountMapper;

    @Resource
    private UserLoginRecordMapper userLoginRecordMapper;

    /**
     * 用户注册
     *
     * @param registerVO
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(RegisterVO registerVO) {
        // 进行用户信息的后端验证
        String mobile = registerVO.getMobile();
        String code = registerVO.getCode();
        String password = registerVO.getPassword();

        Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
        Assert.notEmpty(code, ResponseEnum.CODE_NULL_ERROR);
        Assert.notEmpty(password, ResponseEnum.PASSWORD_NULL_ERROR);
        // 手机号的正泽检验
        Assert.isTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);

        // 验证码的校验
        String redisCode = (String) redisTemplate.opsForValue().get("srb:sms:code:" + mobile);
        // 判断redis的验证码是否为空
        Assert.notEmpty(redisCode, ResponseEnum.REDISCODE_NULL_ERROR);
        assert redisCode != null;
        Assert.equals(redisCode, code, ResponseEnum.CODE_ERROR);

        // 从数据库中查询会员账号信息存不存在
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile", mobile);
        Integer integer = baseMapper.selectCount(wrapper);
        Assert.isTrue(integer == 0, ResponseEnum.MOBILE_EXIST_ERROR);

        // 将用户信息存入到数据库
        UserInfo userInfo = new UserInfo();
        userInfo.setMobile(mobile);
        userInfo.setUserType(registerVO.getUserType());
        userInfo.setName(mobile);
        userInfo.setNickName(mobile);
        userInfo.setPassword(MD5.encrypt(password));
        userInfo.setStatus(UserInfo.STATUS_NORMAL);
        userInfo.setHeadImg(UserInfo.HEAD_IMG);
        baseMapper.insert(userInfo);

        // 创建会员账号
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(userInfo.getId());
        userAccountMapper.insert(userAccount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserInfoVO login(LoginVO loginVO, HttpServletRequest request) {
        Integer userType = loginVO.getUserType();
        String password = loginVO.getPassword();
        String mobile = loginVO.getMobile();
        // 表单的校验
        Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
        Assert.notEmpty(password, ResponseEnum.PASSWORD_NULL_ERROR);

        // 获取ip地址
        String remoteHost = request.getRemoteHost();

        // 判断会员用户是否存在
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile", mobile).eq("user_type", userType);
        UserInfo userInfo = baseMapper.selectOne(wrapper);
        // 用户不存在就抛出异常
        Assert.notNull(userInfo, ResponseEnum.LOGIN_MOBILE_ERROR);

        // 经行密码的校验
        Assert.equals(MD5.encrypt(password), userInfo.getPassword(), ResponseEnum.LOGIN_PASSWORD_ERROR);

        // 判断用户状态是否有效
        Assert.equals(userInfo.getStatus(), UserInfo.STATUS_NORMAL, ResponseEnum.LOGIN_LOKED_ERROR);

        // 记录登录日志
        UserLoginRecord userLoginRecord = new UserLoginRecord();
        userLoginRecord.setUserId(userInfo.getId());
        userLoginRecord.setIp(remoteHost);
        userLoginRecordMapper.insert(userLoginRecord);

        // 生成token
        String token = JwtUtils.createToken(userInfo.getId(), userInfo.getName());
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(userInfo, userInfoVO);
        userInfoVO.setToken(token);
        return userInfoVO;
    }

    /**
     * 获取积分列表
     *
     * @param userInfoQuery
     * @return
     */
    @Override
    public IPage<UserInfo> listPage(Long page, Long limit, UserInfoQuery userInfoQuery) {
        // 组装分页条件
        Page<UserInfo> userInfoPage = new Page<UserInfo>(page, limit);

        Integer userType = userInfoQuery.getUserType();
        String mobile = userInfoQuery.getMobile();
        Integer status = userInfoQuery.getStatus();

        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(mobile), "mobile", mobile)
                .eq(status != null, "status", status)
                .eq(userType != null, "user_type", userType);

        return baseMapper.selectPage(userInfoPage, wrapper);

    }

    /**
     * 锁定和解锁
     *
     * @param id
     * @param status
     */
    @Override
    public void lock(Long id, Integer status) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(id);
        userInfo.setStatus(status);
        baseMapper.updateById(userInfo);
    }

    @Override
    public boolean checkMobile(String mobile) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile", mobile);
        Integer integer = baseMapper.selectCount(wrapper);
        return integer > 0;
    }

    /**
     * 获取个人空间用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserIndexVO getIndexUserInfo(Long userId) {
        //用户信息
        UserInfo userInfo = baseMapper.selectById(userId);

        //账户信息
        QueryWrapper<UserAccount> userAccountQueryWrapper = new QueryWrapper<>();
        userAccountQueryWrapper.eq("user_id", userId);
        UserAccount userAccount = userAccountMapper.selectOne(userAccountQueryWrapper);

        //登录信息
        QueryWrapper<UserLoginRecord> userLoginRecordQueryWrapper = new QueryWrapper<>();
        userLoginRecordQueryWrapper
                .eq("user_id", userId)
                .orderByDesc("id")
                .last("limit 1");
        UserLoginRecord userLoginRecord = userLoginRecordMapper.selectOne(userLoginRecordQueryWrapper);


        //组装结果数据
        UserIndexVO userIndexVO = new UserIndexVO();
        userIndexVO.setUserId(userInfo.getId());
        userIndexVO.setUserType(userInfo.getUserType());
        userIndexVO.setName(userInfo.getName());
        userIndexVO.setNickName(userInfo.getNickName());
        userIndexVO.setHeadImg(userInfo.getHeadImg());
        userIndexVO.setBindStatus(userInfo.getBindStatus());
        userIndexVO.setAmount(userAccount.getAmount());
        userIndexVO.setFreezeAmount(userAccount.getFreezeAmount());
        userIndexVO.setLastLoginTime(userLoginRecord.getCreateTime());

        return userIndexVO;
    }

    /**
     * 根据bindCode 查询手机号
     *
     * @param bindCode
     * @return
     */
    @Override
    public String getMobileByBindCode(String bindCode) {
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("bind_code", bindCode);
        UserInfo userInfo = baseMapper.selectOne(userInfoQueryWrapper);
        return userInfo.getMobile();
    }


}
